#ifndef MORPHOLOGY_H_INCLUDED
#define MORPHOLOGY_H_INCLUDED

#include "image.h"
#include "types.h"

#ifndef NULL
#define NULL 0
#endif

/** \class StructuringElement
*   \brief This class define a structuring element for morphological operations
*/


class StructuringElement : public Binary_Image{
  public:
    ///center
    Position center;

    enum Shape{
    NONE,
    DISK,
    CROSS1,
    CROSS2,
    RECTANGLE,
    ELLIPSE};

    ///Constructor
    /**
    \param height Height
    \param width Width
    \param center Center of element. Default = (0,0).
    \param shape Initial shape
    */
    StructuringElement(int height, int width,Position center = Position(0,0),Shape shape = NONE);

};

/** \class StructuringElement
*   \brief This class contain basic morphological operations
*/

class MOperator {
    public:
        /**Erosion, Simple.
        \param image In image(pointer)
        \param out Out image(pointer), if equal null returned value will be out image
        \param se Structuring Element(pointer)
        \return Out image
        */
        static Grey_Image* erosion(Grey_Image* image,Grey_Image* out,StructuringElement* se);
        static Binary_Image* erosion(Binary_Image* image,Binary_Image* out,StructuringElement* se);

         /**Dilation, Simple.
        \param image In image(pointer)
        \param out Out image(pointer), if equal null returned value will be out image
        \param se Structuring Element(pointer)
        \return Out image
        */
        static Grey_Image* dilation(Grey_Image* image,Grey_Image* out, StructuringElement* se);
        static Binary_Image* dilation(Binary_Image* image,Binary_Image* out, StructuringElement* se);

         /**Thinning by custom Sructuring Element.
        \param image In image(pointer)
        \param out Out image(pointer), if equal null returned value will be out image
        \param foregroud Structuring Element(pointer) for foreground
        \param backgroud Structuring Element(pointer) for background
        \return Out image
        */
        static Grey_Image* thinning(Grey_Image* image,Grey_Image* out,StructuringElement* foreground,StructuringElement* background);
        static Binary_Image* thinning(Binary_Image* image,Binary_Image* out,StructuringElement* foreground,StructuringElement* background);

        /**Thinning by Structuring Element-Golay Letter
        It uses all rotations
        \param image In image(pointer)
        \param out Out image(pointer), if equal null return valueed will be out image
        \param golayletter Structuring Element(pointer)-Golay Letter -> Golay letter could be : "L", "M", "C", "D", "E", "F", "F2", "F3", "H", "I"
        \return Out image
        */
        static Grey_Image* thinning_golay(Grey_Image* image,Grey_Image* out,char* golayletter);
        static Binary_Image* thinning_golay(Binary_Image* image,Binary_Image* out,char* golayletter);

        /**Hit-or-miss by custom Sructuring Element.
        \param image In image(pointer)
        \param out Out image(pointer), if equal null returned value will be out image
        \param foregroud Structuring Element(pointer) for foreground
        \param backgroud Structuring Element(pointer) for background
        \return Out image
        */
        static Grey_Image* hit_or_miss(Grey_Image* image,Grey_Image* out,StructuringElement* foreground,StructuringElement* background);
        static Binary_Image* hit_or_miss(Binary_Image* image,Binary_Image* out,StructuringElement* foreground,StructuringElement* background);

        static Grey_Image* hit_or_miss_golay(Grey_Image* image,Grey_Image* out,char* golayletter,int rotation);
        static Binary_Image* hit_or_miss_golay(Binary_Image* image,Binary_Image* out,char* gollayletter,int rotation);

        /**skeleton of image by structuring element golay "L"
        stop thinning when image stabilize
        obs.: If you know necessary thinnings, "For loop" of thinnings is more fast, because thinning don't test if image stabilize.
        \param image In image(pointer)
        \param out Out image(pointer), if equal null return valueed will be out image
        \return Out image
        */
        static Grey_Image* skel(Grey_Image* image,Grey_Image* out=NULL);
        static Binary_Image* skel(Binary_Image* image,Binary_Image* out=NULL);

        /**Pruning
        stop thinning when image stabilize
        \param image In image(pointer)
        \param out Out image(pointer), if equal null return valueed will be out image
        \param length
        \return Out image
        */
        static Grey_Image* pruning(Grey_Image* image,Grey_Image* out,unsigned int length);
        static Binary_Image* pruning(Binary_Image* image,Binary_Image* out,unsigned int length);

        /**Labelling
        Labelling operation, labellize connected components
        \param image In image(pointer)
        \param out Out image(pointer), if equal null return valueed will be out image
        \return Out image
        */
        static Grey_Image* labelling(Grey_Image* image,Grey_Image* out);
        static Grey_Image* labelling(Binary_Image* image,Grey_Image* out);

        /**Area filter
        Filter image by your connected components. Get components which has area bigger than threshold
        \param image In image(pointer)
        \param out Out image(pointer), if equal null return valueed will be out image
        \param threshold
        \return Out image
        */
        static Grey_Image* areafilter(Grey_Image* image,Grey_Image* out,int threshold);
        static Binary_Image* areafilter(Binary_Image* image,Binary_Image* out,int threshold);

        static Binary_Image* biggerareafilter(Binary_Image* image,Binary_Image* out);

        /**Create one image which has valeu of neighbours
        \param image In image(pointer)
        \param Neighbourhood Default=EIGHTNEIGHBOURHOOD
        \return Out image*/
        static Grey_Image* neighbourvalue(Binary_Image* img,int neighbourhood=EIGHTNEIGHBOURHOOD);

        /**Convert normal skel in one pixel width skel
        \param image In image(pointer)
        \param out Out image(pointer), if equal null return valueed will be out image
        \return Out image*/
        static Binary_Image* onePixelWidth(Binary_Image* img,Binary_Image* out);

};


#endif // MORPHOLOGY_H_INCLUDED
